/***********************************************************************************
Copy right:	    hqyj Tech.
Author:         jiaoyue
Date:           2023.07.01
Description:    http请求处理
***********************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <sqlite3.h>
#include "custom_handle.h"
#include "cJSON.h"
#include "thttpd.h"
#define KB 1024

//普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"

struct msgbuf mq;                               //消息队列对象
static struct std_node *handle_share(int sock); //共享内存函数
int handle_msgqueue(void);                      //消息内存函数
static int handle_login(int sock, const char *input)
{
    char reply_buf[HTML_SIZE] = {0};
    char *uname = strstr(input, "username="); //从返回字符串的第一次的指针
    uname += strlen("username=");             //指针移动到username=后面
    char *p = strstr(input, "password");
    *(p - 1) = '\0'; //username=admin&password=admin 把&变成了\0 作为字符串结束的标志
    printf("username = %s\n", uname);

    char *passwd = p + strlen("password="); //指针移动到password=后面
    printf("passwd = %s\n", passwd);

    sqlite3 *db;
    sqlite3_stmt *stmt;
    const char *sql = "SELECT password FROM user WHERE name = ?";

    // 打开数据库
    if (sqlite3_open("./User.db", &db) != SQLITE_OK)
    {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 预编译SQL语句
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "Failed to prepare statement: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return -1;
    }

    // 绑定用户名到SQL语句
    sqlite3_bind_text(stmt, 1, uname, -1, SQLITE_STATIC);

    int login_success = 0;
    if (sqlite3_step(stmt) == SQLITE_ROW)
    {
        const unsigned char *db_passwd = sqlite3_column_text(stmt, 0);
        if (strcmp((const char *)db_passwd, passwd) == 0)
        {
            login_success = 1;
        }
    }

    sqlite3_finalize(stmt);
    sqlite3_close(db);

    if (login_success)
    {
        sprintf(reply_buf, "<script>localStorage.setItem('usr_user_name', '%s');</script>", uname); // 存到本地仓库里
        strcat(reply_buf, "<script>window.location.href = '/index.html';</script>");                // 跳转到index.html
        send(sock, reply_buf, strlen(reply_buf), 0);
    }
    else
    {
        printf("web login failed\n");

        // "用户名或密码错误"提示
        char out[128] = {0xd3, 0xc3, 0xbb, 0xa7, 0xc3, 0xfb, 0xbb, 0xf2, 0xc3, 0xdc, 0xc2, 0xeb, 0xb4, 0xed, 0xce, 0xf3};
        sprintf(reply_buf, "<script charset='gb2312'>alert('%s');</script>", out);   // 提示对话框
        strcat(reply_buf, "<script>window.location.href = '/login.html';</script>"); // 自己跳转到自己
        send(sock, reply_buf, strlen(reply_buf), 0);
    }

    return 0;
}
static int handle_add(int sock, const char *input)
{
    // mq.type = 10;
    // int number1, number2;
    long type;
    int key, value;
    printf("input:%s\n", input); //显示
    //input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"type=%ldkey=%dvalue=%d\"", &(mq.type), &(mq.key), &(mq.val.b_val)); //将前端的值赋值到后端
    int msgid = handle_msgqueue();
    msgsnd(msgid, &mq, sizeof(mq) - sizeof(long), 0); // 0：代表发完返回否则阻塞  //发送给消息队列

    printf("mq.type:%ld  mq.key:%d  mq.value:%d \n", mq.type, mq.key, mq.val.b_val);

    type = mq.type;
    key = mq.key;
    value = mq.val.b_val;

    char reply_buf[HTML_SIZE] = {0};
    if (type == 10 && key == 104 && value == 1)
    {
        strcpy(reply_buf, "通风扇打开");
    }
    else if (type == 10 && key == 104 && value == 0)
    {
        strcpy(reply_buf, "通风扇关闭");
    }
    else if (type == 10 && key == 105 && value == 1)
    {
        strcpy(reply_buf, "灯打开");
    }
    else if (type == 10 && key == 105 && value == 0)
    {
        strcpy(reply_buf, "灯关闭");
    }
    if (type == 10 && key == 106 && value == 1)
    {
        strcpy(reply_buf, "阀门打开");
    }
    else if (type == 10 && key == 106 && value == 0)
    {
        strcpy(reply_buf, "阀门关闭");
    }
    else if (type == 10 && key == 107 && value == 1)
    {
        strcpy(reply_buf, "报警器打开");
    }
    else if (type == 10 && key == 107 && value == 0)
    {
        strcpy(reply_buf, "报警器关闭");
    }
    //----------------stm32开关-----------------------
    else if (type == 20 && key == 303 && value == 1)
    {
        strcpy(reply_buf, "加湿器打开");
    }
    else if (type == 20 && key == 303 && value == 0)
    {
        strcpy(reply_buf, "加湿器关闭");
    }
    else if (type == 20 && key == 304 && value == 1)
    {
        strcpy(reply_buf, "加热片打开");
    }
    else if (type == 20 && key == 304 && value == 0)
    {
        strcpy(reply_buf, "加热片关闭");
    }
    else if (type == 20 && key == 305 && value == 1)
    {
        strcpy(reply_buf, "风机打开");
    }
    else if (type == 20 && key == 305 && value == 0)
    {
        strcpy(reply_buf, "风机关闭");
    }
    printf("resp = %s\n", reply_buf);
    send(sock, reply_buf, strlen(reply_buf), 0);
    return 0;
}

static struct std_node *handle_share(int sock)
{
    struct shm_param param;
    int shmid;
    int *num = NULL;
    struct std_node *p = NULL;
    //创建或者打开共享内存
    shmid = shm_init(&param, "shm.txt", sizeof(param));
    char reply_buf[HTML_SIZE] = {0};
    if (shmid < 0)
    {
        perror("shm init err\n");
        return NULL;
    }
    printf("共享内存 :shmid: %d\n", shmid);
    //映射共享内存
    num = shm_getaddr(&param);
    p = (struct std_node *)(num + 1);
    if (p == NULL)
    {
        perror("shmat get arr err\n");
        return NULL;
    }
    return p;
}

// 消息队列
// int handle_msgqueue(void)
// {
//     int msgid;
//     struct msgbuf msg;
//     msgid=msg_queue_send("msg",&msg,sizeof(msg),0);
//     if (msgid <=0)
//     {
//         perror("Failed to send message");
//     }
//     printf("消息队列 msgid: %d\n", msgid);
//     return msgid;
// }

//消息队列
int handle_msgqueue(void)
{
    key_t key;
    int msgid;
    if ((key = ftok("/mnt/msg.txt", 'b')) < 0)
    {
        perror("que wangye  ftok err");
        return -1;
    }
    printf("key = %#x\n", key);

    //打开或创建消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666); //创建消息队列，如果之前有就返回-1
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666); //直接打开消息队列
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid handle_msgqueue: %d\n", msgid);
    return msgid;
}

void historical_data_reporting(int sock) //历史数据上报
{
    sqlite3 *db;
    sqlite3_stmt *stmt;

    // 打开数据库连接
    int rc = sqlite3_open("../../sendDate/workshop.db", &db);
    if (rc)
    {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return;
    }

    // 创建 JSON 对象以存储查询结果
    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        fprintf(stderr, "创建 JSON 对象失败\n");
        sqlite3_close(db);
        return;
    }
    cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(4));
    cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));
    cJSON *data = cJSON_CreateObject(); // 用于按key值存储数据
    if (!data)
    {
        fprintf(stderr, "创建 data 对象失败\n");
        cJSON_Delete(root);
        sqlite3_close(db);
        return;
    }
    cJSON_AddItemToObject(root, "data", data);

    // 准备 SQL 语句，只查询 key 值为 301、302、101、102 和 103 的记录
    const char *sql = "SELECT * FROM workshop WHERE key IN (301, 302, 101, 102, 103);";
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL 准备失败: %s\n", sqlite3_errmsg(db));
        cJSON_Delete(root);
        sqlite3_close(db);
        return;
    }
    else
    {
        fprintf(stderr, "SQL 准备成功\n");
    }

    // 执行查询并处理结果
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        int key = sqlite3_column_int(stmt, 1);
        int time = sqlite3_column_int(stmt, 0);
        const char *val = (const char *)sqlite3_column_text(stmt, 2);

        // 打印调试信息
        fprintf(stderr, "key: %d, time: %d, val: %s\n", key, time, val ? val : "(null)");

        // 查找 key 对应的数组
        char key_str[32];
        snprintf(key_str, sizeof(key_str), "%d", key);
        cJSON *key_array = cJSON_GetObjectItem(data, key_str);
        if (!key_array)
        {
            key_array = cJSON_CreateArray();
            if (!key_array)
            {
                fprintf(stderr, "创建 key_array 失败\n");
                continue;
            }
            cJSON_AddItemToObject(data, key_str, key_array);
        }

        // 检查 val 是否为空，若为空则设置为 "N/A"
        const char *value = val ? val : "N/A";

        // 检查数组中是否已经存在相同的时间戳
        int exists = 0;
        for (int i = 0; i < cJSON_GetArraySize(key_array); i++)
        {
            cJSON *item = cJSON_GetArrayItem(key_array, i);
            cJSON *time_item = cJSON_GetObjectItem(item, "time");
            if (time_item && time_item->valueint == time)
            {
                exists = 1;
                break;
            }
        }

        // 如果不存在相同的时间戳，则添加新项
        if (!exists)
        {
            cJSON *item = cJSON_CreateObject();
            if (!item)
            {
                fprintf(stderr, "创建 item 失败\n");
                continue;
            }
            cJSON_AddItemToObject(item, "time", cJSON_CreateNumber(time));
            cJSON_AddItemToObject(item, "val", cJSON_CreateString(value));
            cJSON_AddItemToArray(key_array, item);
        }
    }

    // 清理
    sqlite3_finalize(stmt);
    sqlite3_close(db);

    if (cJSON_GetArraySize(data) > 0)
    {
        char *json_str = cJSON_Print(root);
        if (json_str)
        {
            printf("%s\n", json_str);
            // 发送给网页
            send(sock, json_str, strlen(json_str), 0);
            free(json_str);
        }
        else
        {
            fprintf(stderr, "JSON 打印失败\n");
        }
    }
    else
    {
        printf("没有数据，拼不上啊!!!!!!\n");
    }

    // 清理 root 对象
    cJSON_Delete(root);
}

/**
 * @brief 处理自定义请求，在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    //query_string不一定能用的到
    printf("input:%s\n", input); //浏览器也发过来了list
    //先处理登录操作
    if (strstr(input, "username=") && strstr(input, "password="))
    {
        return handle_login(sock, input);
    }
    //处理求和请求
    else if (strstr(input, "type=") && strstr(input, "key=") && strstr(input, "value="))
    {
        printf("开关控制\n");
        printf("-------%s----%s----%d----\n", __FILE__, __func__, __LINE__);
        return handle_add(sock, input);
    }
    else if (strcmp(input, "list") == 0) //输入list读出设备信息
    {
        printf("-------%s----%s----%d----\n", __FILE__, __func__, __LINE__);
        struct std_node *p = handle_share(sock);
        struct std_node *end = p + (5 * sizeof(struct std_node)); // 计算共享内存5个内存空间
        int num_registers_to_read = 5;                            //共5个寄存器
        int i = 0;
        char buf[32] = {0};
        char buffer[32] = {0};

        //温度、湿度
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);
        p++;

        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);

        //人员计数、粉尘浓度、管道风压
        p = p + 4;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);
        p++;
        sprintf(buffer, "%.2f ", p->new_val.f_val);
        strcat(buf, buffer);
        p++;
        sprintf(buffer, "%.2f ", p->new_val.f_val);
        strcat(buf, buffer);

        // 发送HTTP响应给客户端
        printf("buf:%s\n", buf);
        printf("-------%s----%s----%d----\n", __FILE__, __func__, __LINE__);

        send(sock, buf, strlen(buf), 0);
    }
    else if (strcmp(input, "control") == 0) //输入control读出设备开关信息
    {
        printf("-------%s----%s----%d----\n", __FILE__, __func__, __LINE__);
        struct std_node *p = handle_share(sock);
        struct std_node *end = p + (7 * sizeof(struct std_node)); // 计算共享内存7个内存空间
        int num_registers_to_read = 7;                            //共7个寄存器
        int i = 0;
        char buf[32] = {0};
        char buffer[32] = {0};

        //加湿器
        p = p + 2;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);
        //加热片
        p++;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);
        //风机
        p++;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);

        //通风扇
        p = p + 4;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);
        //灯
        p++;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);
        //报警器
        p++;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);
        //阀门
        p++;
        sprintf(buffer, "%d ", p->new_val.i_val);
        strcat(buf, buffer);

        // 发送HTTP响应给客户端
        printf("buf:%s\n", buf);
        printf("-------%s----%s----%d----\n", __FILE__, __func__, __LINE__);

        send(sock, buf, strlen(buf), 0);
    }
    else if (strcmp(input, "history") == 0) //读取历史数据
    {
        historical_data_reporting(sock);
    }

    else //剩下的都是json请求，这个和协议有关了
    {
        // 构建要回复的JSON数据   //*******JSON********
        const char *json_response = "{\"message\": \"Hello, client!\"}";
        // 发送HTTP响应给客户端
        send(sock, json_response, strlen(json_response), 0);
    }
    return 0;
}
